package com.vogue.supplymall.payment.api.impl;

import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import com.vogue.common.RSAUtils;
import com.vogue.common.http.HttpUtils;
import com.vogue.common.http.Result;
import com.vogue.supplymall.payment.api.WuXiangPayment;
import com.vogue.supplymall.payment.dto.BaseResultParameter;
import com.vogue.supplymall.payment.dto.BaseSimpleInputParameter;
import com.vogue.supplymall.payment.dto.CancelResultParameter;
import com.vogue.supplymall.payment.dto.IResultParameter;
import com.vogue.supplymall.payment.dto.InputParameter;
import com.vogue.supplymall.payment.dto.MultiplePayInputParameter;
import com.vogue.supplymall.payment.dto.PayQueryResultParameter;
import com.vogue.supplymall.payment.dto.PursePayInputParameter;
import com.vogue.supplymall.payment.dto.PursePayResultParameter;
import com.vogue.supplymall.payment.dto.ResultParameter;
import com.vogue.supplymall.payment.dto.SinglePayInputParameter;
import com.vogue.supplymall.payment.tools.AESUtil;

@Service("wuXiangPayment")
public class WuXiangPaymentImpl implements WuXiangPayment {
    
    private static final long serialVersionUID = -3139742394267239180L;

    public static final Logger LOGGER_WUXIANGPAYMENTIMPL = LoggerFactory.getLogger(WuXiangPaymentImpl.class);
    
    /** 请求头header中需要含有的关键字 */
    private static final String HEAD_KEY = "tcslKey";
        
    /** 调用接口头类型 */
    private static final String CONTENT_TYPE = "application/x-www-form-urlencoded";
    
    private static Gson json = new GsonBuilder()
            .registerTypeAdapter(Double.class, 
                    new JsonSerializer<Double>()  {
                        @Override
                        public JsonElement serialize(Double value,
                        Type theType, JsonSerializationContext context) {
                            if (value.isNaN()) {
                                return new JsonPrimitive(0); // Convert NaN to zero
                            } else if (value.isInfinite() || value.doubleValue()<0.01) {
                                return new JsonPrimitive(value); // Leave small numbers and infinite alone
                            } else {
                                // Keep 2 decimal digits only
                                return new JsonPrimitive((new BigDecimal(value)).setScale(2, BigDecimal.ROUND_HALF_DOWN));
                            }
                        }
                })
                .create();
    
    /**
     * 支付宝获取支付连接(生成二维码链接)
     * @param parameter 订单数据信息
     * @param commPayGetUrl 对接吾享支付接口获取支付二维码连接接口地址
     * @param publickey64 对接加密公钥字符串(Base64编码后的)由吾享提供 结尾必须以 == 结束
     * @return
     * @throws Exception 
     */
    public ResultParameter commPayGetUrl(InputParameter parameter, String commPayGetUrl, String publickey64) throws Exception {
        
        if(commPayGetUrl == null) {
            throw new Exception("缺少获取支付二维码的接口地址");
        }
        
        if(publickey64 == null) {
            throw new Exception("缺少必要的公钥");
        }else {
            if(!publickey64.endsWith("==")) {
                publickey64 += "==";
            }
        }
        LOGGER_WUXIANGPAYMENTIMPL.info("======支付宝获取支付连接(生成二维码链接)Begin======");
        LOGGER_WUXIANGPAYMENTIMPL.info("地址：{} 公钥：{} 参数：{} ", commPayGetUrl, publickey64, parameter.toString());
        LOGGER_WUXIANGPAYMENTIMPL.info("======支付宝获取支付连接(生成二维码链接)End======");
        String resultStr = getRemoteResultStr(parameter, commPayGetUrl, publickey64);
        LOGGER_WUXIANGPAYMENTIMPL.info("======支付宝获取支付连接(生成二维码链接)Result-Begin======");
        LOGGER_WUXIANGPAYMENTIMPL.info("订单{}的结果：{}", parameter.getData().getOrderid(), resultStr);
        LOGGER_WUXIANGPAYMENTIMPL.info("======支付宝获取支付连接(生成二维码链接)Result-End======");
        ResultParameter result = json.fromJson(resultStr, ResultParameter.class);
        return result;
    }

    /**
     * 商龙云钱包支付连接(获取支付网页的参数及提交表单数据的地址)
     * @param parameter 订单数据信息
     * @param commPayGetUrl 对接吾享支付接口获取支付二维码连接接口地址
     * @param publickey64 对接加密公钥字符串(Base64编码后的)由吾享提供 结尾必须以 == 结束
     * @return
     * @throws Exception 
     */
    public PursePayResultParameter pursePayGetUrl(PursePayInputParameter parameter, String pursePayGetUrl, String publickey64) throws Exception {
        
        if(pursePayGetUrl == null) {
            throw new Exception("缺少获取商龙云钱包支付的接口地址");
        }
        
        if(publickey64 == null) {
            throw new Exception("缺少必要的公钥");
        }else {
            if(!publickey64.endsWith("==")) {
                publickey64 += "==";
            }
        }
        LOGGER_WUXIANGPAYMENTIMPL.info("======商龙云钱包支付连接(获取支付网页的参数及提交表单数据的地址)Begin======");
        LOGGER_WUXIANGPAYMENTIMPL.info("地址：{} 公钥：{} 参数：{} ", pursePayGetUrl, publickey64, parameter.toString());
        LOGGER_WUXIANGPAYMENTIMPL.info("======商龙云钱包支付连接(获取支付网页的参数及提交表单数据的地址)End======");
        String resultStr = getRemoteResultStr(parameter, pursePayGetUrl, publickey64);
        LOGGER_WUXIANGPAYMENTIMPL.info("======商龙云钱包支付连接(获取支付网页的参数及提交表单数据的地址)Result-Begin======");
        LOGGER_WUXIANGPAYMENTIMPL.info("订单{}的结果：{}", parameter.getOrderid(), resultStr);
        LOGGER_WUXIANGPAYMENTIMPL.info("======商龙云钱包支付连接(获取支付网页的参数及提交表单数据的地址)Result-End======");
        PursePayResultParameter result = json.fromJson(resultStr, PursePayResultParameter.class);
        return result;
    }

    /**
     * 撤销支付接口
     * @param payCancelInputParameter 订单数据信息
     * @param commPayCancelUrl 对接吾享支付接口撤销支付接口地址
     * @param publickey64 对接加密公钥字符串(Base64编码后的)由吾享提供 结尾必须以 == 结束
     * @return
     * @throws Exception
     */
    public CancelResultParameter commPayCancel(BaseSimpleInputParameter payCancelInputParameter, String commPayCancelUrl, String publickey64) throws Exception {
        
        if(commPayCancelUrl == null) {
            throw new Exception("缺少撤销订单的接口地址");
        }
        
        if(publickey64 == null) {
            throw new Exception("缺少必要的公钥");
        }else {
            if(!publickey64.endsWith("==")) {
                publickey64 += "==";
            }
        }
        LOGGER_WUXIANGPAYMENTIMPL.info("======撤销支付接口Begin======");
        LOGGER_WUXIANGPAYMENTIMPL.info("地址：{} 公钥：{} 参数：{} ", commPayCancelUrl, publickey64, payCancelInputParameter.toString());
        LOGGER_WUXIANGPAYMENTIMPL.info("======撤销支付接口End======");
        String resultStr = getRemoteResultStr(payCancelInputParameter, commPayCancelUrl, publickey64);
        LOGGER_WUXIANGPAYMENTIMPL.info("======撤销支付接口Result-Begin======");
        LOGGER_WUXIANGPAYMENTIMPL.info("订单{}的结果：{}", payCancelInputParameter.getOrderid(), resultStr);
        LOGGER_WUXIANGPAYMENTIMPL.info("======撤销支付接口Result-End======");
        CancelResultParameter result = json.fromJson(resultStr, CancelResultParameter.class);
        return result;
    }
    
    /**
     * 支付状态查询接口
     * @param payQueryInputParameter    查询参数
     * @param url   查询路径
     * @param publickey64   查询数据混淆字符串
     * @return
     * @throws Exception
     */
    public IResultParameter queryPayState(BaseSimpleInputParameter payQueryInputParameter, String url, String publickey64) throws Exception {
        
        if(url == null) {
            throw new Exception("缺少查询订单状态的地址");
        }
        
        if(publickey64 == null) {
            throw new Exception("缺少必要的公钥");
        }else {
            if(!publickey64.endsWith("==")) {
                publickey64 += "==";
            }
        }
        LOGGER_WUXIANGPAYMENTIMPL.info("======支付状态查询接口Begin======");
        LOGGER_WUXIANGPAYMENTIMPL.info("地址：{} 公钥：{} 参数：{} ", url, publickey64, payQueryInputParameter.toString());
        LOGGER_WUXIANGPAYMENTIMPL.info("======支付状态查询接口End======");
        String resultStr = getRemoteResultStr(payQueryInputParameter, url, publickey64);
        LOGGER_WUXIANGPAYMENTIMPL.info("======支付状态查询接口Result-Begin======");
        LOGGER_WUXIANGPAYMENTIMPL.info("订单{}的结果：{}", payQueryInputParameter.getOrderid(), resultStr);
        LOGGER_WUXIANGPAYMENTIMPL.info("======支付状态查询接口Result-End======");
        IResultParameter result = json.fromJson(resultStr, BaseResultParameter.class);
        if (result.getReturnCode() == 1) {
            result = (IResultParameter) json.fromJson(resultStr, PayQueryResultParameter.class);
        }        
        return result;
    }
    
    /**
     * 支付订单关单接口
     * @param payCloseInputParameter 订单数据信息
     * @param commPayCloseUrl 对接吾享关单接口地址
     * @param publickey64 对接加密公钥字符串(Base64编码后的)由吾享提供 结尾必须以 == 结束
     * @return
     * @throws Exception
     */
    public BaseResultParameter commPayClose(BaseSimpleInputParameter payCloseInputParameter, String commPayCloseUrl, String publickey64) throws Exception {
        
        if(commPayCloseUrl == null) {
            throw new Exception("缺少关单的地址");
        }
        
        if(publickey64 == null) {
            throw new Exception("缺少必要的公钥");
        }else {
            if(!publickey64.endsWith("==")) {
                publickey64 += "==";
            }
        }
        LOGGER_WUXIANGPAYMENTIMPL.info("======支付订单关单接口Begin======");
        LOGGER_WUXIANGPAYMENTIMPL.info("地址：{} 公钥：{} 参数：{} ", commPayCloseUrl, publickey64, payCloseInputParameter.toString());
        LOGGER_WUXIANGPAYMENTIMPL.info("======支付订单关单接口End======");
        String resultStr = getRemoteResultStr(payCloseInputParameter, commPayCloseUrl, publickey64);
        LOGGER_WUXIANGPAYMENTIMPL.info("======支付订单关单接口Result-Begin======");
        LOGGER_WUXIANGPAYMENTIMPL.info("订单{}的结果：{}", payCloseInputParameter.getOrderid(), resultStr);
        LOGGER_WUXIANGPAYMENTIMPL.info("======支付订单关单接口Result-End======");
        BaseResultParameter result = json.fromJson(resultStr, BaseResultParameter.class);
        return result;
    }
    
    /**
     * 公用的调用吾享URL接口返回结果数据的处理方法
     * 
     * @param inputObj
     * @param url
     * @param publickey64
     * @return
     * @throws Exception
     */
    private String getRemoteResultStr(Object inputObj, String url, String publickey64) throws Exception {
        
        Map<String,String> headers = new HashMap<>();
        
        Map<String,String> params = new HashMap<>();
        
        String ckey = AESUtil.getRandomkey64();
        
        String tcslKey = ckey + "_" + (System.currentTimeMillis() / 1000);  
        
        tcslKey = RSAUtils.RSAEncode(publickey64, tcslKey);
        
        headers.put(HEAD_KEY, tcslKey);
        
        headers.put("Content-Type", CONTENT_TYPE);
        
        String data = AESUtil.encrypt(ckey, json.toJson(inputObj));

        params.put("data", data);
        
        Result result = HttpUtils.post(url, params, headers, "UTF-8"); 
        
        return AESUtil.decrpyt(ckey, result.getResult());
    }

    /**
     * 多单合并支付接口
     * @param multiplePayInputParameter 多订单封装数据
     * @param payUrl 支付接口url
     * @param publickey64 对接加密公钥字符串(Base64编码后的)由吾享提供 结尾必须以 == 结束
     * @return 支付结果
     * @throws Exception 错误异常
     */
    @Override
    public IResultParameter mergePay(MultiplePayInputParameter multiplePayInputParameter, String payUrl,
            String publickey64) throws Exception {
        if(payUrl == null) {
            throw new Exception("缺少关单的地址");
        }
        
        if(publickey64 == null) {
            throw new Exception("缺少必要的公钥");
        }else {
            if(!publickey64.endsWith("==")) {
                publickey64 += "==";
            }
        }
        LOGGER_WUXIANGPAYMENTIMPL.info("======多单合并支付接口Begin======");
        LOGGER_WUXIANGPAYMENTIMPL.info("地址：{} 公钥：{} 参数：{} ", payUrl, publickey64, multiplePayInputParameter.toString());
        LOGGER_WUXIANGPAYMENTIMPL.info("======多单合并支付接口End======");
        String resultStr = getRemoteResultStr(multiplePayInputParameter, payUrl, publickey64);
        LOGGER_WUXIANGPAYMENTIMPL.info("======多单合并支付接口Result-Begin======");
        LOGGER_WUXIANGPAYMENTIMPL.info("结果：{}", resultStr);
        LOGGER_WUXIANGPAYMENTIMPL.info("======多单合并支付接口Result-End======");
        IResultParameter result = json.fromJson(resultStr, BaseResultParameter.class);
        return result;
    }

    /**
     * 单笔支付接口
     * @param multiplePayInputParameter 多订单封装数据
     * @param payUrl 支付接口url
     * @param publickey64 对接加密公钥字符串(Base64编码后的)由吾享提供 结尾必须以 == 结束
     * @return 支付结果
     * @throws Exception 错误异常
     */
    @Override
    public IResultParameter singlePay(SinglePayInputParameter singlePayInputParameter, String payUrl,
            String publickey64) throws Exception {
        if(payUrl == null) {
            throw new Exception("缺少关单的地址");
        }
        
        if(publickey64 == null) {
            throw new Exception("缺少必要的公钥");
        }else {
            if(!publickey64.endsWith("==")) {
                publickey64 += "==";
            }
        }
        LOGGER_WUXIANGPAYMENTIMPL.info("======单笔支付接口Begin======");
        LOGGER_WUXIANGPAYMENTIMPL.info("地址：{} 公钥：{} 参数：{} ", payUrl, publickey64, singlePayInputParameter.toString());
        LOGGER_WUXIANGPAYMENTIMPL.info("======单笔支付接口End======");
        String resultStr = getRemoteResultStr(singlePayInputParameter, payUrl, publickey64);
        LOGGER_WUXIANGPAYMENTIMPL.info("======单笔支付接口Result-Begin======");
        LOGGER_WUXIANGPAYMENTIMPL.info("订单{}的结果：{}", singlePayInputParameter.getOrderid(), resultStr);
        LOGGER_WUXIANGPAYMENTIMPL.info("======单笔支付接口Result-End======");
        IResultParameter result = json.fromJson(resultStr, BaseResultParameter.class);
        return result;
    }
}
